#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include "../md5/md5.c"
#include "../DES/des.c"
#include "MsgType.h"

// Step1 接收消息C和D
void ReceiveFromClient(MsgC *msgC, MsgD *msgD);
// Step2 解密消息B
void DecryptMsgB(MsgB msgB, char *K_TGS, MsgB *De_msgB);
// Step3 解密消息D
void DecryptMsgD(MsgD msgD, char *K_CT, MsgD *De_msgD);
// Step4 认证
bool AuthenticateClient(MsgB De_msgB, MsgD De_msgD);
void CreateMsgE(MsgE *msgE, char *serviceID, MsgB De_msgB, char *K_CS, char *K_SS);
void CreateMsgF(MsgF *msgF, char *K_CS,  char *K_CT);
// Step5 发送消息
void SendToClient(MsgE msgE, MsgF msgF);

int main()
{
    char *K_TGS = "TGS's secret key"; // TGS密钥(TGS's secret key)
    char *K_SS = "service's secret key";
    MsgC msgC;
    MsgD msgD;
    MsgB De_msgB;
    MsgD De_msgD;
    MsgE msgE;
    MsgF msgF;
    MsgCInit(&msgC);
    MsgDInit(&msgD);
    MsgBInit(&De_msgB);
    MsgDInit(&De_msgD);
    MsgEInit(&msgE);
    MsgFInit(&msgF);

    msgD.timestamp = "Empty";
    while (1)
    {
        ReceiveFromClient(&msgC, &msgD);
        if (msgD.timestamp != "Empty")
        {
            printf("......\n接收消息C和消息D\n");
            break;
        }
    }
        
    DecryptMsgB(msgC.msgB, K_TGS, &De_msgB);
    DecryptMsgD(msgD, De_msgB.K_CT, &De_msgD);
    
    CreateMsgE(&msgE, msgC.serviceID, De_msgB, De_msgB.K_CT, K_SS);
    CreateMsgF(&msgF, De_msgB.K_CT, De_msgB.K_CT);    
    
    if(AuthenticateClient(De_msgB, De_msgD)){
        SendToClient(msgE, msgF);
    }
    
    exit(EXIT_SUCCESS);
}

// Step1 接收消息C和D
void ReceiveFromClient(MsgC *msgC, MsgD *msgD)
{
    struct msg_st data;
    long int msgtype = 0;
    //建立消息队列
    int msgid = msgget((key_t)113, 0666 | IPC_CREAT);
    if (msgid == -1)
    {
        perror("msgget failed");
        exit(EXIT_FAILURE);
    }

    if (msgrcv(msgid, (void *)&data, BUFSIZ, msgtype, 0) == -1)
    {
        perror("msgcrv failed");
        exit(EXIT_FAILURE);
    }
    strcpy(msgC->serviceID, data.text);

    if (msgrcv(msgid, (void *)&data, BUFSIZ, msgtype, 0) == -1)
    {
        perror("msgcrv failed");
        exit(EXIT_FAILURE);
    }
    strcpy(msgC->msgB.clientID, data.text);
    
    if (msgrcv(msgid, (void *)&data, BUFSIZ, msgtype, 0) == -1)
    {
        perror("msgcrv failed");
        exit(EXIT_FAILURE);
    }
    strcpy(msgC->msgB.clientAddr, data.text);

    if (msgrcv(msgid, (void *)&data, BUFSIZ, msgtype, 0) == -1)
    {
        perror("msgcrv failed");
        exit(EXIT_FAILURE);
    }
    strcpy(msgC->msgB.vaildity, data.text);

    if (msgrcv(msgid, (void *)&data, BUFSIZ, msgtype, 0) == -1)
    {
        perror("msgcrv failed");
        exit(EXIT_FAILURE);
    }
    strcpy(msgC->msgB.K_CT, data.text);
    
    if (msgrcv(msgid, (void *)&data, BUFSIZ, msgtype, 0) == -1)
    {
        perror("msgcrv failed");
        exit(EXIT_FAILURE);
    }
    strcpy(msgD->clientID, data.text);
    
    msgD->timestamp = (char *)malloc(BUFSIZ*sizeof(char));
    if (msgrcv(msgid, (void *)&data, BUFSIZ, msgtype, 0) == -1)
    {
        perror("msgcrv failed");
        exit(EXIT_FAILURE);
    }
    strcpy(msgD->timestamp, data.text);

    // 删除消息队列
    if (msgctl(msgid, IPC_RMID, 0) == -1)
    {
        perror("msgclt failed");
        exit(EXIT_FAILURE);
    }
}

// Step2 解密消息B
void DecryptMsgB(MsgB msgB, char *K_TGS, MsgB *De_msgB)
{
    De_msgB->clientID = DecryptionBS(msgB.clientID, K_TGS);
    De_msgB->clientAddr = DecryptionBS(msgB.clientAddr, K_TGS);
    De_msgB->vaildity = DecryptionBS(msgB.vaildity, K_TGS);
    De_msgB->K_CT = DecryptionBS(msgB.K_CT, K_TGS);  
}

// Step3 解密消息D
void DecryptMsgD(MsgD msgD, char *K_CT, MsgD *De_msgD){
    De_msgD->clientID = DecryptionBS(msgD.clientID, K_CT);
    De_msgD->timestamp = DecryptionBS(msgD.timestamp, K_CT);
}

// Step4 认证
bool AuthenticateClient(MsgB De_msgB, MsgD De_msgD){    
    if(strcmp(De_msgB.clientID, De_msgD.clientID) == 0){
        printf("......\n票据TGT认证成功\n");
        return true;
    }else{
        printf("......\n票据TGT认证失败\n");
        return false;
    }
}

void CreateMsgE(MsgE *msgE, char *serviceID, MsgB De_msgB, char *K_CS, char *K_SS){
    strcpy(msgE->serviceID, serviceID);
    // ST    
    msgE->clientID = EncryptionBS(De_msgB.clientID, K_SS);
    msgE->clientAddr = EncryptionBS(De_msgB.clientAddr, K_SS);
    msgE->vaildity = EncryptionBS(De_msgB.vaildity, K_SS);
    msgE->K_CS = EncryptionBS(K_CS, K_SS);
}

void CreateMsgF(MsgF *msgF, char *K_CS,  char *K_CT){
    msgF->K_CS = EncryptionBS(K_CS, K_CT);
}

// Step5 发送消息
void SendToClient(MsgE msgE, MsgF msgF)
{
    struct msg_st data;
    long int msgtype = 0;
    //建立消息队列
    int msgid = msgget((key_t)114, 0666 | IPC_CREAT);
    if (msgid == -1)
    {
        perror("msgget failed");
        exit(EXIT_FAILURE);
    }

    data.msg_type = 1;
    strcpy(data.text, msgE.serviceID);
    if(msgsnd(msgid, (void*)&data, BUFSIZ, 0) == -1)  
    {  
        perror("msgsnd failed\n");
        exit(EXIT_FAILURE);  
    }

    strcpy(data.text, msgE.clientID);
    if(msgsnd(msgid, (void*)&data, BUFSIZ, 0) == -1)  
    {  
        perror("msgsnd failed\n");
        exit(EXIT_FAILURE);  
    }

    strcpy(data.text, msgE.clientAddr);
    if(msgsnd(msgid, (void*)&data, BUFSIZ, 0) == -1)  
    {  
        perror("msgsnd failed\n");
        exit(EXIT_FAILURE);  
    }

    strcpy(data.text, msgE.vaildity);
    if(msgsnd(msgid, (void*)&data, BUFSIZ, 0) == -1)  
    {  
        perror("msgsnd failed\n");
        exit(EXIT_FAILURE);  
    }

    strcpy(data.text, msgE.K_CS);
    if(msgsnd(msgid, (void*)&data, BUFSIZ, 0) == -1)  
    {  
        perror("msgsnd failed\n");
        exit(EXIT_FAILURE);  
    }   

    strcpy(data.text, msgF.K_CS);
    if(msgsnd(msgid, (void*)&data, BUFSIZ, 0) == -1)  
    {  
        perror("msgsnd failed\n");
        exit(EXIT_FAILURE);  
    }
    printf("......\n发送消息E和消息F到客户机\n");
}